package cn.starrysky108.simpleerp.core.handler;


import cn.starrysky108.simpleerp.core.base.BaseResponseEntity;
import cn.starrysky108.simpleerp.core.exception.ApiException;
import cn.starrysky108.simpleerp.core.enums.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;

/**
 * @author Carl Lee
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理Api异常
     *
     * @return HttpResultVO 统一格式返回
     */
    @ExceptionHandler(value = ApiException.class)
    public BaseResponseEntity<Object> apiException(ApiException e) {
        log.error("异常详情", e);
        return BaseResponseEntity.failure(e.getCodeEnum(), e.getData());
    }

    /**
     * 处理Validate数据校验异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public BaseResponseEntity<String> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        //将ObjectError的所有错误组合返回
        StringBuilder buffer = new StringBuilder();
        for (ObjectError objectError : e.getBindingResult().getAllErrors()) {
            buffer.append(objectError.getDefaultMessage()).append(";");
        }
        log.info("异常详情", e);
        //返回异常信息
        return BaseResponseEntity.failure(ResultCodeEnum.VALIDATE_FAIL, buffer.toString());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public BaseResponseEntity<String> missingServletRequestParameterException(MissingServletRequestParameterException e) {
        //缺少参数
        log.info("异常详情", e);
        //返回异常信息
        return BaseResponseEntity.failure(ResultCodeEnum.VALIDATE_FAIL, "缺少参数" + e.getParameterName());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public BaseResponseEntity<String> bindException(MissingServletRequestParameterException e) {
        //缺少参数
        log.info("异常详情", e);
        //返回异常信息
        return BaseResponseEntity.failure(ResultCodeEnum.BIND_FAIL, e.getMessage());
    }

    /**
     * 处理来自数据库的异常
     *
     * @param exception datastore exception
     * @return response
     */
    @ExceptionHandler(DataAccessException.class)
    BaseResponseEntity<DataAccessException> handleDataAccessException(DataAccessException exception) {
        String errorMessage = "[数据库异常]" + exception.getMessage();
        log.warn(errorMessage, exception);
        return BaseResponseEntity.failure(errorMessage);
    }

    /**
     * 处理 接口无权访问异常AccessDeniedException FORBIDDEN(403, "Forbidden"),
     */
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(AccessDeniedException.class)
    public BaseResponseEntity<AccessDeniedException> accessDeniedException(AccessDeniedException e) {
        log.info("权限不足[403]{}", e.getMessage());
        return BaseResponseEntity.failure(ResultCodeEnum.FORBIDDEN);
    }


    /**
     * 404异常处理
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NoHandlerFoundException.class)
    public BaseResponseEntity<Object> noHandlerFoundException(NoHandlerFoundException e) {
        log.info("无法访问[404]{}", e.getMessage());
        return BaseResponseEntity.failure(ResultCodeEnum.NOT_FOUND);
    }

    /**
     * 处理其他bad请求异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = RestClientResponseException.class)
    public BaseResponseEntity<Throwable> badRequestException(RestClientResponseException e, HttpServletResponse response) {
        log.error("bad请求[{}]{}", e.getRawStatusCode(), e.getMessage());
        response.setStatus(e.getRawStatusCode());
        return BaseResponseEntity.failure(e.getRawStatusCode(), e.getStatusText(), e);
    }

    /**
     * 参数异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public BaseResponseEntity<String> assertException(IllegalArgumentException e) {
        log.error("Assert异常[-3]{}", e.getMessage());
        return BaseResponseEntity.failure(ResultCodeEnum.ASSERT_FAIL, e.getMessage());
    }

    /**
     * 处理所有异常，默认错误码-1
     *
     * @return HttpResultVO 统一格式返回
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public BaseResponseEntity<String> defaultException(Exception e) {
        log.error("服务器异常[500]{}", e.getMessage(), e);
        return BaseResponseEntity.failure(ResultCodeEnum.SERVER_ERROR, e.getMessage());
    }
}
